#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include "log.h"
#include "http_server.h"
#include "methods.h"

static char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

void log_request (struct tm *local_time, http_connection_t *http_connection, host_t *host)
{
	struct iovec vector[8];
	char timestamp[128];
	int timestamplen;
	char peer[20];
	size_t peerlen;
	char filesize[32];
	int filesizelen;

	if (host->fd == -1) {
		return;
	}

	if (!inet_ntop (AF_INET, &(http_connection->sin.sin_addr), peer, sizeof (peer))) {
		return;
	}

	peerlen = strlen (peer);

	vector[0].iov_base = "[";
	vector[0].iov_len = 1;

	vector[1].iov_base = peer;
	vector[1].iov_len = peerlen;

	timestamplen = snprintf (timestamp, sizeof (timestamp), "] [%s, %02d %s %d %02d:%02d:%02d] [%.*s http://", days[local_time->tm_wday], local_time->tm_mday, months[local_time->tm_mon], 1900 + local_time->tm_year, local_time->tm_hour, local_time->tm_min, local_time->tm_sec, (unsigned) methods[http_connection->http_method].len, methods[http_connection->http_method].string);

	vector[2].iov_base = timestamp;
	vector[2].iov_len = timestamplen;

	vector[3].iov_base = (void *) host->host_name;
	vector[3].iov_len = host->host_name_length;

	vector[4].iov_base = http_connection->path.data;
	vector[4].iov_len = http_connection->path.used - 1;

	vector[5].iov_base = "] [";
	vector[5].iov_len = 3;

	if (http_connection->user_agent.used > 0) {
		vector[6].iov_base = http_connection->user_agent.data;
		vector[6].iov_len = http_connection->user_agent.used;
	} else {
		vector[6].iov_base = "-";
		vector[6].iov_len = 1;
	}

	if (http_connection->response_type == DIRECTORY_LISTING_RESPONSE) {
		filesizelen = snprintf (filesize, sizeof (filesize), "] [%u]\n", (unsigned) http_connection->message_body.used);
	} else {
		filesizelen = snprintf (filesize, sizeof (filesize), "] [%lld]\n", http_connection->filesize);
	}

	vector[7].iov_base = filesize;
	vector[7].iov_len = filesizelen;

	writev (host->fd, vector, 8);
}

void proxy_log_request (struct tm *local_time, http_connection_t *http_connection, buffer_t *host)
{
	struct iovec vector[6];
	char timestamp[128];
	int timestamplen;
	char peer[20];
	size_t peerlen;

	if (!inet_ntop (AF_INET, &(http_connection->sin.sin_addr), peer, sizeof (peer))) {
		return;
	}

	peerlen = strlen (peer);

	vector[0].iov_base = "[";
	vector[0].iov_len = 1;

	vector[1].iov_base = peer;
	vector[1].iov_len = peerlen;

	timestamplen = snprintf (timestamp, sizeof (timestamp), "] [%s, %02d %s %d %02d:%02d:%02d] [%.*s http://", days[local_time->tm_wday], local_time->tm_mday, months[local_time->tm_mon], 1900 + local_time->tm_year, local_time->tm_hour, local_time->tm_min, local_time->tm_sec, (unsigned) methods[http_connection->http_method].len, methods[http_connection->http_method].string);

	vector[2].iov_base = timestamp;
	vector[2].iov_len = timestamplen;

	vector[3].iov_base = (void *) host->data;
	vector[3].iov_len = host->used - 1;

	vector[4].iov_base = http_connection->path.data;
	vector[4].iov_len = http_connection->path.used - 1;

	vector[5].iov_base = "]\n";
	vector[5].iov_len = 2;

	writev (http_server.proxy_log_fd, vector, 6);
}

void log_error (const char *format, ...)
{
	va_list ap;
	struct tm *local_time;

	buffer_reset (&http_server.logbuffer);

	local_time = &http_server.local_time;
	if (buffer_format (&http_server.logbuffer, "[%s, %02d %s %d %02d:%02d:%02d] ", days[local_time->tm_wday], local_time->tm_mday, months[local_time->tm_mon], 1900 + local_time->tm_year, local_time->tm_hour, local_time->tm_min, local_time->tm_sec) < 0) {
		return;
	}

	va_start (ap, format);

	if (buffer_vformat (&http_server.logbuffer, format, ap) < 0) {
		va_end (ap);
		return;
	}

	va_end (ap);

	if (buffer_append_char (&http_server.logbuffer, '\n') < 0) {
		return;
	}

	write (http_server.log_fd, http_server.logbuffer.data, http_server.logbuffer.used);
}
